package modele.worldAgent;

import java.awt.Color;
import java.util.ArrayList;
import java.util.Random;

import utility.Position;

import modele.Square;
import modele.World;
import modele.WorldElem.Flooded;
import modele.WorldElem.SecondaryState;
import modele.WorldElem.State;

public class Wolf extends Agent{
	
	public final int view = 20;
	public final int timeWithoutMeal = 200;
	public int timeSinceLastMeal;
	public int[] randMovement;
	
	public Wolf(int posX, int posY, World w) {
		super(posX, posY, w);
		timeSinceLastMeal = 0;
	}
	
	
	
	protected void initWeight(){
		
		agentWeight = new int[NBAGENT];
		agentWeight[SHEEP] = ATTRACTSIGNE * 20;
		agentWeight[WOLF] = ATTRACTSIGNE * 10;
		agentWeight[PATOU] = REPULSESIGNE * 150;
		
		stateWeight = new int[State.NBSTATE];
		stateWeight[State.EARTH] = 0;
		stateWeight[State.GRASS] = 0;
		stateWeight[State.ROCK] = 0;
		stateWeight[State.SAND] = 0;
		stateWeight[State.TREE] = 0;
		
		secondaryStateWeight = new int[SecondaryState.NBSECONDARYSTATE];
		secondaryStateWeight[SecondaryState.BURNING] = REPULSESIGNE * 15;
		secondaryStateWeight[SecondaryState.FLOODED] = REPULSESIGNE * 3;
		secondaryStateWeight[SecondaryState.NONE] = 0;
		
		distanceWeight = new int[view];
		for(int i = 0 ; i < view ; i++){
			distanceWeight[i] = (int) Math.pow(view - i, 2);
		}
	}

	
	@Override
	public void step() {
		weightStep();
//		randomStep();
	}

	
	public void weightStep() {
		timeSinceLastMeal++;
		int[] movement = new int[Direction.nbDirection];
		for(int i = 0 ; i < movement.length ; i++){
			movement[i] = 0;
		}
		ArrayList<ArrayList<Square>> squares = getSquare().getSquareAround(getWorld(), view);
		for(ArrayList<Square> als : squares){
			for(Square sLoop : als ){
				int[] movementLoop = getMovementToAgent(sLoop.getPosX(), sLoop.getPosY());
				int weight = getWeight(sLoop.getPosX(), sLoop.getPosY(), getSpeedMovement(movementLoop));
				movementLoop = applyWeight(weight, movementLoop);
				
				movement = addMovement(movement, movementLoop);
			}
		}
		movement = normalizeMovement(movement);
		
		Random r = new Random();
		if(isStatic(movement) ){
			if(randMovement == null || r.nextFloat() > 1.5F 
					|| posX == world.getWidth() - 1
					|| posX == 0
					|| posY == world.getWidth() - 1
					|| posX == 0){
				randomStep();
			}
			else{
				Position p = getFinalPosition(randMovement);
				setPosition(p.getX(), p.getY());
			}
		}
		else{
			Position p = getFinalPosition(movement);
			setPosition(p.getX(), p.getY());
		}
		
	}
	
	
	
	
	public void randomStep(){
		int indexX = 0 , indexY = 0;
		Random r = new Random();
		indexX = posX + r.nextInt(3) - 1;
		indexY = posY + r.nextInt(3) - 1;
		
		indexX = Math.max(0, indexX);
		indexX = Math.min(world.getWidth() - 1, indexX);
		indexY = Math.max(0, indexY);
		indexY = Math.min(world.getWidth() - 1, indexY);
		randMovement = getMovementToAgent(indexX, indexY);
		randMovement = applyWeight(ATTRACTSIGNE, randMovement);
		if(world.getAgent(indexX, indexY) == null){
			setPosition(indexX, indexY);
		}
	}

	@Override
	public int getId() {
		return WOLF;
	}

	@Override
	public Color getColor() {
		return Color.BLACK;
	}

	@Override
	public int getMaxSpeed() {
		return 1;
	}

	@Override
	public int getWeight(int posX, int posY, int distance) {
		if(distance == 0 ){
			return 0;
		}
		int somme = 0;
		int tmp = 0;
		int weightDistance  = distanceWeight[distance - 1];
		Agent a = getAgent(posX, posY);
		if( a != null){
			tmp = agentWeight[getAgent(posX,posY).getId()];
//			if(tmp != 0 && tmp/Math.abs(tmp) == REPULSESIGNE){
			somme += tmp * weightDistance;
//			}
//			else{
//				somme+=tmp;		
//			}
		}
		Square s = world.getSquare(posX, posY);
		tmp = stateWeight[s.getStateValue()];
//		if(tmp != 0 && tmp/Math.abs(tmp) == REPULSESIGNE){
			somme += tmp * weightDistance;
//		}
//		else{
//			somme+= tmp;		
//		}
		
		tmp = secondaryStateWeight[s.getSecondaryStateValue()];
//		if(tmp != 0 && tmp/Math.abs(tmp) == REPULSESIGNE){
			somme += tmp * weightDistance;
//		}
//		else{
//			somme+=tmp;		
//		}
		return somme;
	}


	
	public int[] normalizeMovement(int[] movement) {
		if(movement.length != Direction.nbDirection){
			return null;
		}
		
		int[] result = new int[Direction.nbDirection];
		result[Direction.NORTH.getValue()] = Math.max(0, movement[Direction.NORTH.getValue()] - movement[Direction.NORTH.getInverseValue()]);
		result[Direction.EAST.getValue()] = Math.max(0, movement[Direction.EAST.getValue()] - movement[Direction.EAST.getInverseValue()]);
		result[Direction.SOUTH.getValue()] = Math.max(0, movement[Direction.SOUTH.getValue()] - movement[Direction.SOUTH.getInverseValue()]);
		result[Direction.WEST.getValue()] = Math.max(0, movement[Direction.WEST.getValue()] - movement[Direction.WEST.getInverseValue()]);
		for( int i = 0 ; i < Direction.nbDirection ; i++){
			if(result[i] != 0){
				result[i] /= result[i];
			}
		}
		return result;
	}



	@Override
	public void survive() {
		Square s = world.getSquare(posX, posY);
		if(timeSinceLastMeal >= timeWithoutMeal){
			this.setDie();
		}
		else if(s.getSecondaryStateValue() == SecondaryState.BURNING){
			this.setDie();
		}
		else if(s.getSecondaryStateValue() ==  SecondaryState.FLOODED){
			if(((Flooded) s.getSecondaryState()).getWaterLevel() > 2){
				this.setDie();
			}
		}
		
	}
	
	@Override
	public void setPosition(int posX, int posY){
		Agent a = world.getAgent(posX, posY);
		if(a == null || a.getId() == SHEEP){
			if(a!=null){
				a.setDie();
				timeSinceLastMeal = 0;
			}
			world.getAgentsMap()[this.posX][this.posY] = null; 
			this.posX = posX;
			this.posY = posY;
			world.getAgentsMap()[posX][posY] = this;
		}
	}
	
}